class MisMatchError(BaseException):
    pass


class Separator(object):
    def __call__(self, x_list, i, *args, **kwargs):
        raise NotImplementedError()


class Str(Separator):
    def __init__(self, string):
        self.string = string

    def __call__(self, x_list, i, allow_skip=False, *args, **kwargs):
        if not self.string: return i, i, None
        if allow_skip:
            for i in range(i, len(x_list)):
                if x_list[i] == self.string:
                    return i, i + 1, None
            raise MisMatchError("mismatch {} vs .".format(self.string))
        else:
            if x_list[i] == self.string:
                return i, i + 1, None
            else:
                raise MisMatchError("mismatch {} vs {}.".format(self.string, x_list[i]))

    def __repr__(self):
        return "Str({})".format(self.string)

    def __str__(self):
        return self.__repr__()


class Null(Str):
    def __init__(self):
        super().__init__("")


class Var(Separator):
    def __init__(self, name):
        self.name = name

    def __call__(self, x_list, i, *args, **kwargs):
        return i, i + 1, {self.name: x_list[i]}

    def __repr__(self):
        return "Var({})".format(self.name)

    def __str__(self):
        return self.__repr__()


class LongVar(Separator):
    def __init__(self, name):
        self.name = name

    def __repr__(self):
        return "LongVar({})".format(self.name)

    def __str__(self):
        return self.__repr__()


def valid_bracket(record, k, left_item='<', right_item='>'):
    """
    找到与左尖括号匹配的右尖括号，k表示左尖括号出现的index
    """
    bracket = 1
    for i in range(k, len(record)):
        token = record[i]
        if token == left_item:
            bracket += 1
        elif token == right_item:
            bracket -= 1
        if bracket == 0:
            return i
    return None


class Scope(Separator):
    def __init__(self, left, right):
        self.left, self.right = left, right

    def __call__(self, x_list, i, allow_skip=False):
        left_i = -1
        if allow_skip:
            for i in range(i, len(x_list)):
                if x_list[i] == self.left:
                    left_i = i
        else:
            if x_list[i] == self.left:
                left_i = i
        if left_i < 0:
            raise MisMatchError("mismatch {} vs .".format(self.left))

        right_i = valid_bracket(x_list, left_i + 1, self.left, self.right)
        if right_i is None:
            raise MisMatchError("mismatch {} vs .".format(self.right))

        return left_i, right_i + 1, None

    def __repr__(self):
        return "Scope({}...{})".format(self.left, self.right)

    def __str__(self):
        return self.__repr__()


class Or(Separator):
    def __init__(self, *seperators):
        self.separators = SeparatorTool.to(seperators)

    def __call__(self, x_list, i, *args, **kwrag):
        for sep in self.separators:
            try:
                res = sep(x_list, i)
                return res
            except MisMatchError as e:
                pass
        raise MisMatchError("mismatch.")

    def __repr__(self):
        return "Or{}".format(self.separators)

    def __str__(self):
        return self.__repr__()


class Loop(Separator):
    def __init__(self, *patterns):
        self.patterns = patterns


class SeparatorTool(object):
    @staticmethod
    def to(seperators):
        seps = []
        for sep in seperators:
            if isinstance(sep, str):
                seps.append(Str(sep))
            elif isinstance(sep, (list, tuple)):
                seps.append(SeperatorList(SeparatorTool.to(sep)))
            elif isinstance(sep, Separator):
                seps.append(sep)
            else:
                raise TypeError("")
        return seps


class SeperatorList(Separator, list):
    def __init__(self, seperators):
        super(SeperatorList, self).__init__(SeparatorTool.to(seperators))
        if isinstance(seperators[-1], LongVar):
            raise TypeError("last one of SeperatorList can not be LongVar")

    def __call__(self, x_list, i=0, *args, **kwargs):
        separators = self

        def deal_long_var(pre_longvar, j):
            if pre_longvar is not None:
                l_idx, l_i = pre_longvar
                resutls[l_idx] = (l_i, j, {separators[l_idx].name: x_list[l_i:j]})

        start_i = i
        pre_longvar = None
        resutls = [None] * len(separators)
        for sep_i, sep in enumerate(separators):
            if isinstance(sep, LongVar):
                if pre_longvar is not None:
                    raise ValueError("LongVar can not be neighbours.")
                pre_longvar = (sep_i, i)
            elif isinstance(sep, Separator):
                resutls[sep_i] = j, i, _ = sep(x_list, i, allow_skip=pre_longvar is not None)
                deal_long_var(pre_longvar, j)
                pre_longvar = None
            else:
                raise ValueError("must be seperator")

            if i >= len(x_list): break
        deal_long_var(pre_longvar, i)
        return start_i, i, resutls


if __name__ == "__main__":
    separators = SeperatorList([Or("class", "def"), Var("classname"), ":", Var("superclass"), LongVar("classbody")])
    x_list = "def A : B { ... } ;".split()
    print(x_list)
    print(separators(x_list))
